package com.pickgliss.ui
{
	import com.pickgliss.toplevel.StageReferance;
	import com.pickgliss.ui.core.Component;
	import com.pickgliss.ui.core.ITipedDisplay;
	import com.pickgliss.ui.core.ITransformableTipedDisplay;
	import com.pickgliss.ui.tip.ITip;
	import com.pickgliss.ui.tip.ITransformableTip;
	import com.pickgliss.ui.vo.DirectionPos;
	import com.pickgliss.utils.Directions;
	import com.pickgliss.utils.DisplayUtils;
	import com.pickgliss.utils.ObjectUtils;
	
	import flash.display.DisplayObject;
	import flash.display.DisplayObjectContainer;
	import flash.display.IDisplayObject;
	import flash.display.Stage;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	import flash.utils.Dictionary;

	public final class ShowTipManager
	{
		public static const StartPoint:Point = new Point(0,0);
		private static var _instance:ShowTipManager;

		public static function get Instance():ShowTipManager
		{
			if(_instance == null)
			{
				_instance = new ShowTipManager();
			}
			return _instance;
		}
		
		public function ShowTipManager()
		{
			_tips = new Dictionary();
			_tipedObjects = new Vector.<ITipedDisplay>();
		}
		
		private var _currentTipObject:ITipedDisplay;
		private var _simpleTipset:Object;
		private var _tipContainer:DisplayObjectContainer;
		private var _tipedObjects:Vector.<ITipedDisplay>;
		private var _tips:Dictionary;

		/**
		 * 
		 * @param tipedDisplay 显示tip的鼠标相应对象
		 * 
		 */		
		public function addTip(tipedDisplay:ITipedDisplay):void
		{
			if(tipedDisplay == null)return;
			removeTipedObject(tipedDisplay);
			_tipedObjects.push(tipedDisplay);
			tipedDisplay.addEventListener(MouseEvent.ROLL_OVER,__onOver);
			tipedDisplay.addEventListener(MouseEvent.ROLL_OUT,__onOut);
			if(_currentTipObject == tipedDisplay)
			{
				showTip(_currentTipObject);
			}
		}
		/**
		 * 
		 * @param tip 所要显示的tip
		 * @param target 显示tip的鼠标相应对象
		 * @param direction tip所显示的方向
		 * @return tip所显示的位置（以target的注册点为注册点）
		 * 
		 */		
		public function getTipPosByDirction(tip:ITip,target:ITipedDisplay,direction:int):Point
		{
			var resultPos:Point = new Point();
			if(direction == Directions.DIRECTION_T)
			{
				resultPos.y = - tip.height - target.tipGapV;
				resultPos.x = (target.width - tip.width)/2;
			}else if(direction == Directions.DIRECTION_L)
			{
				resultPos.x = - tip.width - target.tipGapH;
				resultPos.y = (target.height - tip.height)/2;
			}else if(direction == Directions.DIRECTION_R)
			{
				resultPos.x = target.width + target.tipGapH;
				resultPos.y = (target.height - tip.height)/2;
			}else if(direction == Directions.DIRECTION_B)
			{
				resultPos.y = target.height + target.tipGapV;
				resultPos.x = (target.width - tip.width)/2;
			}else if(direction == Directions.DIRECTION_TL)
			{
				resultPos.y = - tip.height - target.tipGapV;
				resultPos.x = - tip.width - target.tipGapH;
			}else if(direction == Directions.DIRECTION_TR)
			{
				resultPos.y = - tip.height - target.tipGapV;
				resultPos.x = target.width + target.tipGapH;
			}else if(direction == Directions.DIRECTION_BL)
			{
				resultPos.y = target.height + target.tipGapV;
				resultPos.x = - tip.width - target.tipGapH;
			}else if(direction == Directions.DIRECTION_BR)
			{
				resultPos.y = target.height + target.tipGapV;
				resultPos.x = target.width + target.tipGapH;
			}
			return resultPos;
		}
		/**
		 * 
		 * @param target 所要隐藏tip的目标对象
		 * 
		 */		
		public function hideTip(target:ITipedDisplay):void
		{
			if(target == null)return;
			var tip:ITip = _tips[target.tipStyle];
			if(tip == null)return;
			if(_tipContainer.contains(tip.asDisplayObject()))
			{
				_tipContainer.removeChild(tip.asDisplayObject());
			}
			_currentTipObject = null;
		}
		
		public function removeCurrentTip():void
		{
			hideTip(_currentTipObject);
		}
		
		public function removeAllTip():void
		{
			for each(var tip:ITip in _tips)
			{
				if(tip.asDisplayObject().parent)tip.asDisplayObject().parent.removeChild(tip.asDisplayObject());
			}
		}
		
		/**
		 * 
		 * @param tipedDisplay 所要移除的tip的目标对象
		 * 
		 */		
		public function removeTip(tipedDisplay:ITipedDisplay):void
		{
			removeTipedObject(tipedDisplay);
			if(_currentTipObject == tipedDisplay)hideTip(_currentTipObject);
		}
		/**
		 * 设置简单的tip
		 * @param target tip的目标对象
		 * @param tipMsg tip的内容
		 * 
		 */		
		public function setSimpleTip(target:ITipedDisplay,tipMsg:String = ""):void
		{
			if(_simpleTipset == null)return;
			if(target is Component)Component(target).beginChanges();
			target.tipStyle = _simpleTipset.tipStyle;
			target.tipData = tipMsg;
			target.tipDirctions = _simpleTipset.tipDirctions;
			target.tipGapV = _simpleTipset.tipGapV;
			target.tipGapH = _simpleTipset.tipGapH;
			if(target is Component)Component(target).commitChanges();
		}
		/**
		 * 
		 */		
		public function setup():void
		{
			_tipContainer = LayerManager.Instance.getLayerByType(LayerManager.GAME_TOP_LAYER);
		}
		/**
		 * 显示tip
		 * @param target 显示tip的对象, target 必须实现ITipedDisplay接口 或 ITransformableTipedDisplay接口, 否则无任何效果
		 * 
		 */		
		public function showTip(target:*):void
		{
			var tip:* = _tips[target.tipStyle];
			if(target is ITipedDisplay){
				setCommonTip(target,tip);
				tip = _tips[target.tipStyle];
			}
			if(target is ITransformableTipedDisplay){
				tip.tipWidth = target.tipWidth;
				tip.tipHeight = target.tipHeight;
			}
			configPosition(target,tip);
			_currentTipObject = target;
			_tipContainer.addChild(tip.asDisplayObject());
			
		}
		
		public function getTipInstanceByStylename(stylename:String):ITip
		{
			return _tips[stylename];
		}
		
		private var _updateTempTarget:ITipedDisplay;
		public function updatePos():void
		{
			if(!_updateTempTarget)return;
			showTip(_updateTempTarget);
		}
		
		private function setCommonTip(target:*,tip:*):void{
			if(tip == null)
			{
				if(target.tipStyle == null)return;
				tip = createTipByStyleName(target.tipStyle);
				if(tip == null) return;
			}
			tip.tipData = target.tipData;
		}
		
		public function createTipByStyleName(stylename:String):*{
			_tips[stylename] = ComponentFactory.Instance.creat(stylename);
			return _tips[stylename];
		}
		
		private function configPosition(target:*,tip:*):void{
			var startPos:Point = _tipContainer.globalToLocal(target.localToGlobal(StartPoint));
			var resultPos:Point = new Point();
			
			var resultDirection:DirectionPos = getTipPriorityDirction(tip,target,target.tipDirctions);
			resultPos = getTipPosByDirction(tip,target,resultDirection.direction);
			if(resultDirection.offsetX < int.MAX_VALUE/2)
			{
				tip.x = resultPos.x+startPos.x+resultDirection.offsetX;
			}else
			{
				tip.x = resultPos.x+startPos.x
			}
			if(resultDirection.offsetY < int.MAX_VALUE/2)
			{
				tip.y = resultPos.y+startPos.y+resultDirection.offsetY;
			}else
			{
				tip.y = resultPos.y+startPos.y
			}
		}
		
		private function __onOut(event:MouseEvent):void
		{
			var target:ITipedDisplay = event.currentTarget as ITipedDisplay;
			hideTip(target);
			_updateTempTarget=null;
		}
		
		private function __onOver(event:MouseEvent):void
		{
			var target:ITipedDisplay = event.currentTarget as ITipedDisplay;
			if(target.tipStyle == null)return;
			showTip(target);
			_updateTempTarget=target;
		}
		
		private function getTipPriorityDirction(tip:ITip,target:ITipedDisplay,directions:String):DirectionPos
		{
			var dirs:Array = directions.split(",");
			var resultDirectionPos:DirectionPos;
			var tempDirectionPos:Vector.<DirectionPos> = new Vector.<DirectionPos>();
			var startPos:Point = _tipContainer.globalToLocal(target.localToGlobal(StartPoint));
			for(var i:int = 0;i<dirs.length;i++)
			{
				var ordinaryPos:Point = getTipPosByDirction(tip,target,dirs[i]);
				var resultStartPos:Point = new Point(ordinaryPos.x+startPos.x,ordinaryPos.y+startPos.y);
				var resultEndPos:Point = new Point(ordinaryPos.x+startPos.x+tip.width,ordinaryPos.y+startPos.y+tip.height);
				var directionPos:DirectionPos = creatDirectionPos(resultStartPos,resultEndPos,int(dirs[i]));
				if(directionPos.offsetX == 0 && directionPos.offsetY == 0)
				{
					resultDirectionPos = directionPos;
					break;
				}else
				{
					tempDirectionPos.push(directionPos);
				}
			}
			if(resultDirectionPos == null)resultDirectionPos = searchFixedDirectionPos(tempDirectionPos);
			return resultDirectionPos;
		}
		
		private function searchFixedDirectionPos(tempDirections:Vector.<DirectionPos>):DirectionPos
		{
			var result:DirectionPos;
			var reverDirections:Vector.<DirectionPos> = tempDirections.reverse();
			for(var i:int = 0;i<reverDirections.length;i++)
			{
				if(result == null)
				{
					result = reverDirections[i];
				}else
				{
					var current:int = Math.abs(reverDirections[i].offsetX) + Math.abs(reverDirections[i].offsetY);
					var last:int = Math.abs(result.offsetX) + Math.abs(result.offsetY);
					if(current <= last)result = reverDirections[i];
				}
			}
			return result;
		}
		
		private function creatDirectionPos(startPos:Point,endPos:Point,direction:int):DirectionPos
		{
			var directionPos:DirectionPos = new DirectionPos();
			directionPos.direction = direction;
			if(direction == Directions.DIRECTION_T)
			{
				if(startPos.y < 0 )
				{
					directionPos.offsetY = int.MAX_VALUE/2;
				}else
				{
					directionPos.offsetY = 0;
				}
				if(startPos.x < 0)
				{
					directionPos.offsetX = - startPos.x;
				}else if(endPos.x > StageReferance.stageWidth)
				{
					directionPos.offsetX = StageReferance.stageWidth - endPos.x;
				}else
				{
					directionPos.offsetX = 0;
				}
			}else if(direction == Directions.DIRECTION_L)
			{
				if(startPos.x < 0 )
				{
					directionPos.offsetX = int.MAX_VALUE/2;
				}else
				{
					directionPos.offsetX = 0;
				}
				if(startPos.y < 0)
				{
					directionPos.offsetY = - startPos.y;
				}else if(endPos.y > StageReferance.stageHeight)
				{
					directionPos.offsetY = StageReferance.stageHeight - endPos.y;
				}else
				{
					directionPos.offsetY = 0;
				}
			}else if(direction == Directions.DIRECTION_R)
			{
				if(endPos.x > StageReferance.stageWidth )
				{
					directionPos.offsetX = int.MAX_VALUE/2;
				}else
				{
					directionPos.offsetX = 0;
				}
				if(startPos.y < 0)
				{
					directionPos.offsetY = - startPos.y;
				}else if(endPos.y > StageReferance.stageHeight)
				{
					directionPos.offsetY = StageReferance.stageHeight - endPos.y;
				}else
				{
					directionPos.offsetY = 0;
				}
			}else if(direction == Directions.DIRECTION_B)
			{
				if(endPos.y >  StageReferance.stageHeight)
				{
					directionPos.offsetY = int.MAX_VALUE/2;
				}else
				{
					directionPos.offsetY = 0;
				}
				if(startPos.x < 0)
				{
					directionPos.offsetX = - startPos.x;
				}else if(endPos.x > StageReferance.stageWidth)
				{
					directionPos.offsetX = StageReferance.stageWidth - endPos.x;
				}else
				{
					directionPos.offsetX = 0;
				}
			}else 
			{
				if(DisplayUtils.isInTheStage(startPos) && DisplayUtils.isInTheStage(endPos))
				{
					directionPos.offsetX = 0;
					directionPos.offsetY = 0;
				}else
				{
					directionPos.offsetY = int.MAX_VALUE/2;
					directionPos.offsetX = int.MAX_VALUE/2;
				}
			}
			return directionPos;
		}
		
		private function removeTipedObject(tipedDisplay:ITipedDisplay):void
		{
			var index:int = _tipedObjects.indexOf(tipedDisplay);
			tipedDisplay.removeEventListener(MouseEvent.ROLL_OVER,__onOver);
			tipedDisplay.removeEventListener(MouseEvent.ROLL_OUT,__onOut);
			if( index != -1)
			{
				_tipedObjects.splice(index,1);
			}
		}
	}
}